/***************************************************
> Copyright (C) 2025 ==ASD== All rights reserved.
> File Name: hw8.c
> Author: asd
> Mail:3319941451@qq.com 
> Created Time: 2025年01月03日 星期五 20时51分33秒
***************************************************/
//服务器端补包模块
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mysql/mysql.h>

#include "cJSON.h"

#define DB_HOST "localhost"
#define DB_USER "root"
#define DB_PASSWORD "Aa123!"
#define DB_NAME "client"

// 定义结构体存储数据包信息
typedef struct Packet {
    int sequence_number;
    char data[1024];
} Packet;

// 全局变量，用于存储已接收数据包的序列号
int received_sequence_numbers[100];
int received_sequence_count = 0;

// 函数声明
void handle_client_request(int client_socket);
MYSQL *mysql_connection();
void request_missing_packets(int client_socket,int sequence_number);

int main() {
    // 创建TCP套接字用于接收客户端补包请求
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("Socket creation failed");
        exit(-1);
    }

    // 设置服务器地址结构体
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6868);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    // 绑定套接字到地址和端口
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("Bind failed");
        exit(-1);
    }

    // 监听套接字
    if (listen(server_socket, 5) == -1) {
        perror("Listen failed");
        exit(-1);
    }

    // 创建epoll实例
    int epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("Epoll create failed");
        exit(-1);
    }

    // 将服务器套接字添加到epoll监听事件中
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = server_socket;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_socket, &event) == -1) {
        perror("Epoll ctl add server socket failed");
        exit(-1);
    }

    // 主循环，等待事件发生
    struct epoll_event events[10];
    while (1) {
        int num_events = epoll_wait(epoll_fd, events, 10, -1);
        if (num_events == -1) {
            perror("Epoll wait failed");
            break;
        }

        for (int i = 0; i < num_events; i++) {
            if (events[i].data.fd == server_socket) {
                // 接受客户端连接
                struct sockaddr_in client_addr;
                socklen_t client_addr_len = sizeof(client_addr);
                int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);
                if (client_socket == -1) {
                    perror("Accept failed");
                } else {
                    // 将客户端套接字添加到epoll监听事件中
                    event.events = EPOLLIN;
                    event.data.fd = client_socket;
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_socket, &event) == -1) 
					{
                        perror("Epoll ctl add client socket failed");
                    }
                }
            } else 
			{
                // 处理客户端请求
                handle_client_request(events[i].data.fd);
            }
        }
    }

    // 关闭服务器套接字
    close(server_socket);

    return 0;
}

void handle_client_request(int client_socket) 
{
    // 接收客户端发送的已接收数据包序列号信息
    char buffer[100];
	char type[20];
	int cnt = 0;
    int ret = recv(client_socket, buffer, sizeof(buffer), 0);
    if (ret == -1) 
	{
        perror("Recv failed");
    } else if (ret == 0) 
	{
        // 客户端关闭连接
        printf("Client disconnected\n");
        close(client_socket);
    } else 
	{
			int sequence_number = 0;
			cJSON *json = NULL;
			cJSON *node = NULL;
			json = cJSON_Parse(buffer);
			node = cJSON_GetObjectItem(json, "type");
			if (node == NULL) 
			{
				printf("can't find\n");
				exit(-1);
			}
			if (node->type == cJSON_String) 
			{
			 strcpy(type, node->valuestring);
			}
			if(!strcmp(type,"resupply"))
			{
				node = cJSON_GetObjectItem(json, "cnt");
				if (node == NULL) 
				{
					printf("can't find\n");
					exit(-1);
				}
				if (node->type == cJSON_Number) 
				{
					cnt = node->valueint;
				}
			
            // 有丢包，向客户端发送丢失数据包的请求
            request_missing_packets(client_socket,cnt);
			}else if(!strcmp(type,"logout"))
			{
				logout_client_info(client_socket);
			}
    }
}

MYSQL *mysql_connection()
{
	MYSQL *conn;

    conn = mysql_init(NULL);
    if (!mysql_real_connect(conn, DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, 0, NULL, 0)) {
        fprintf(stderr, "数据库连接失败: %s\n", mysql_error(conn));
        exit(EXIT_FAILURE);
    }
	return conn;
}

void request_missing_packets(int client_socket,int cnt) {
    MYSQL *conn = mysql_connection();
	int ret;
	
	mysql_query(conn, "SET NAMES utf8"); // 设置中文字符集

	char sql_buf[128] = "select * from data where  sequence_number  = cnt";
	ret = mysql_query(conn, sql_buf); // 执行sql语句
	if (ret != 0) {
		printf("mysql query failed\n");
	}
	MYSQL_RES *res;
	MYSQL_ROW row;
	
	res = mysql_store_result(conn); // 存储结果
	int client_id[50];
	memset(&client_id,0,sizeof(client_id));
	for (int i = 0;i < mysql_num_rows(res); i++) 
	{ // 行
		row = mysql_fetch_row(res);
		for (int j = 0;j < mysql_num_fields(res); j++) 
		{
			if(cnt == atoi(row[j]))
			{
			int file_fd = open("row[j+1]", O_RDONLY);
				if (file_fd == -1) {
					perror("Open missing packet file failed");
					return;
				}

				char buffer[1024];
				int ret = 0;
				ret = read(file_fd, buffer, sizeof(buffer));
				while (ret > 0) 
				{
					ret = send(client_socket, buffer, strlen(buffer), 0);
					if (ret == -1) 
					{
						perror("send");
					}
				}
				 close(file_fd);
			}
		}
	}
    /*int file_fd = open("missing_packet.txt", O_RDONLY);
    if (file_fd == -1) {
        perror("Open missing packet file failed");
        return;
    }

    char buffer[1024];
    int ret = 0;
	ret = read(file_fd, buffer, sizeof(buffer));
    while (ret > 0) 
	{
        if (send(client_socket, buffer, bytes_read, 0) == -1) {
            perror("Send missing packet failed");
        }
    }*/

}
void logout_client_info(int client_socket)
{
	MYSQL *conn = mysql_connection();
	int ret = 0;
	char temp[1024] = "";;
	char ID[20] = "";
	char list[30] = ""; 
	
	sprintf(table_name,"delete from client_enroll where socket = '%s'",client_socket);
	
	ret = mysql_query(conn,table_name); // 执行sql语句
	if (ret != 0) {
		printf("数据库执行失败\n");
	}
}